<template>
  <div class="dw-tree">
    <div class="search-warpper" v-if="showSearch">
      <el-input size="small" placeholder="输入名称或拼音首字母搜索" v-model="keyword" @keyup.enter.stop="onSearch">
        <template #append>
          <el-button :icon="Search" @click="onSearch" />
        </template>
      </el-input>
    </div>
    <div v-loading="loading" class="tree">
      <el-empty v-show="dataSource?.length === 0">
        <template #image> </template>
        <el-button type="primary" @click="addRootNode">新增</el-button>
      </el-empty>
      <el-tree
        ref="treeRef"
        v-show="dataSource?.length > 0"
        element-loading-text="数据加载中..."
        style="height: 100%"
        :data="dataSource"
        :props="defaultProps"
        node-key="id"
        default-expand-all
        :expand-on-click-node="expandOnClickNode"
        @current-change="currentChange"
        @node-click="nodeClick"
        :highlight-current="true"
      >
        <template #default="{ node, data }">
          <div :class="readonly ? 'tree-node' : 'tree-node-edit'">
            <div v-if="node.data.isEdit && !readonly" style="width: calc(100% - 60px); display: flex">
              <slot name="edit-contanier" :data="data" :node="node">
                <div style="width: 100%; display: flex" v-if="props.treeProps && props.treeProps.code">
                  <el-input size="small" v-model="data[props.treeProps.code]" style="width: 50%" placeholder="编码"></el-input>
                  <el-input size="small" style="width: 50%" v-model="data[props.treeProps.label]" @keyup.enter.stop="save(node, data)" placeholder="名称"></el-input>
                </div>
                <div style="width: 100%; display: flex" v-else>
                  <el-input size="small" v-model="data[props.treeProps.label]" @keyup.enter.stop="save(node, data)"></el-input>
                </div>
              </slot>
            </div>
            <div style="display: flex; align-items: center" v-else>
              <slot name="icon" :data="data">
                <el-icon><Folder /></el-icon>
              </slot>
              <div style="padding-left: 6px">{{ node.label }}</div>
            </div>
            <div style="padding-right: 10px; position: absolute; right: 0; display: flex">
              <div
                class="total"
                v-if="
                  (props.treeProps && props.treeProps.total !== undefined && props.showRootTotalNum && node.data.systemDefault === 1) ||
                  (props.treeProps && props.treeProps.total !== undefined && node.data.systemDefault !== 1)
                "
              >
                {{ node.data[props.treeProps.total] }}
              </div>
              <div class="button-box" v-if="!readonly">
                <el-space v-if="node.data.isEdit">
                  <el-tooltip effect="dark" content="提交" placement="bottom">
                    <el-icon class="icon save" @click.stop="save(node, data)">
                      <CircleCheckFilled />
                    </el-icon>
                  </el-tooltip>
                  <el-tooltip effect="dark" content="撤销" placement="bottom">
                    <el-icon class="icon del" @click.stop="cancel(node, data)">
                      <RefreshLeft />
                    </el-icon>
                  </el-tooltip>
                </el-space>
                <el-space v-else>
                  <el-tooltip effect="dark" content="新增" placement="bottom" v-if="allowLevelNum === 0 || (allowLevelNum !== 0 && node.level < allowLevelNum)">
                    <el-icon class="icon add" @click.stop="add(node, data)"><CirclePlus /></el-icon>
                  </el-tooltip>
                  <el-tooltip effect="dark" content="编辑" placement="bottom" v-if="node.data.systemDefault !== 1">
                    <el-icon class="icon add" @click.stop="edit(node, data)"> <EditPen /></el-icon>
                  </el-tooltip>
                  <el-tooltip effect="dark" content="删除" placement="bottom" v-if="node.data.systemDefault !== 1">
                    <el-icon class="icon del" @click.stop="del(node, data)"><Delete /></el-icon>
                  </el-tooltip>
                </el-space>
              </div>
            </div>
          </div>
        </template>
      </el-tree>
    </div>
  </div>
</template>
<script lang="ts" setup generic="T extends ITreeEntity">
import type Node from 'element-plus/es/components/tree/src/model/node.mjs';
import { Search } from '@element-plus/icons-vue';
import { computed, markRaw, onMounted, ref, type PropType } from 'vue';
import { nanoid } from 'nanoid';
import { dwHttp } from '@/utils/http';
import { ElMessageBox } from 'element-plus';
import { QuestionFilled } from '@element-plus/icons-vue';
import type { ITreeEntity, ITreeProp } from '@/types/entity';
import type { IResponseData } from '@/types/http';
import { translateDataToTree } from '@/utils/func';
defineOptions({
  name: 'DwTree',
});

const props = defineProps({
  showSearch: {
    type: Boolean,
    default: () => {
      return true;
    },
  },
  data: {
    type: Array as PropType<T[]>,
    default: () => {
      return [];
    },
  },
  dataForm: {
    type: String,
    default: () => {
      return 'service';
    },
  },
  allowLevelNum: {
    type: Number,
    default: () => {
      return 0;
    },
  },
  dataType: {
    type: String,
    default: () => {
      return 'parentId'; //parentId
    },
  },
  readonly: {
    type: Boolean,
    default: () => {
      return false;
    },
  },
  showRootTotalNum: {
    type: Boolean,
    default: () => {
      return false;
    },
  },
  getTreeUrl: {
    type: String,
  },
  addTreeUrl: {
    type: String,
  },
  editTreeUrl: {
    type: String,
  },
  delTreeUrl: {
    type: String,
  },
  treeProps: {
    type: Object as PropType<ITreeProp>,
    default: () => {
      return { label: 'domainName', code: 'code', children: 'children', total: 'totalNum' };
    },
  },
  expandOnClickNode: {
    type: Boolean,
    default: false,
  },
});

const treeRef = ref();
const keyword = ref<string>('');
const emits = defineEmits(['currentChange', 'nodeClick']);
const loading = ref<boolean>(false);
const dataSource = ref<T[]>(props.data);
const editType = ref<'add' | 'edit'>('add');
const labelClone = ref<string>('');
const showSearch = ref<boolean>(props.showSearch);
const readonly = ref<boolean>(props.readonly);

const allowLevelNum = props.allowLevelNum;

onMounted(() => {
  reload();
});
const reload = () => {
  if (props.dataForm !== 'service') {
    return;
  }
  loading.value = true;

  dwHttp({
    method: 'get',
    url: props.getTreeUrl,
    params: { keyword: keyword.value },
    isSuccessTip: false,
  })
    .then((res: unknown) => {
      const { data } = res as IResponseData<T>;
      if (props.dataType == 'parentId') {
        const result = translateDataToTree(data as unknown as T[]);
        dataSource.value = result as unknown as T[];
      } else {
        dataSource.value = data as unknown as T[];
      }
    })
    .finally(() => {
      loading.value = false;
    });
};
const defaultProps = {
  children: props.treeProps.children,
  label: props.treeProps.label,
};
const add = (node: Node, data: T) => {
  editType.value = 'add';
  const children: T[] = [];
  const newChild = {
    id: nanoid(),
    parentId: data.id || '0',
    children: children,
    isEdit: true,
  };
  if (!data.children) {
    data.children = [];
  }
  data.children.push(newChild);
  node.expanded = true;
};
const edit = (node: Node, data: T) => {
  editType.value = 'edit';
  //@ts-ignore
  labelClone.value = data[props.treeProps.label] as string;
  node.data.isEdit = true;
  console.log(node);
  console.log(data);
};
const del = (node: Node, data: T) => {
  if (props.dataForm !== 'service') return;
  let url = props.delTreeUrl;
  if (!url) {
    return;
  }
  url = url?.replace('{id}', data.id);

  ElMessageBox.confirm('确认删除当前节点?', '询问', {
    icon: markRaw(QuestionFilled),
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    dwHttp({
      method: 'delete',
      url: url,
    }).then(() => {
      reload();
    });
  });
};
const cancel = (node: Node, data: ITreeEntity) => {
  if (editType.value === 'add') {
    const parent = node.parent;
    const children: ITreeEntity[] = parent?.data.children || [];
    const index = children.findIndex((d) => d.id === data.id);
    children.splice(index, 1);
  } else {
    node.data[props.treeProps.label] = labelClone.value;
    node.data.isEdit = false;
  }
};
const save = async (node: Node, data: ITreeEntity) => {
  if (props.dataForm !== 'service') {
    emits('currentChange', data, node.data.isEdit, node);
    node.data.isEdit = false;
    return;
  }
  dwHttp({
    method: editType.value === 'add' ? 'post' : 'put',
    url: props.addTreeUrl,
    data: data,
  }).then(() => {
    emits('currentChange', data, node.data.isEdit, node);
    node.data.isEdit = false;
  });
};
const currentChange = (data: ITreeEntity, node: Node) => {
  emits('currentChange', data, node.data.isEdit, node);
};
const nodeClick = (data: ITreeEntity, node: Node) => {
  emits('nodeClick', data, node.data.isEdit, node);
};

const onSearch = () => {
  reload();
};
const getCurrentNode = () => {
  return treeRef.value.getCurrentNode();
};
const setCurrentKey = (key: string, shouldAutoExpandParent: boolean) => {
  treeRef.value.setCurrentKey(key, shouldAutoExpandParent);
};

const setTreeData = (data: T[]) => {
  dataSource.value = data;
};
const getTreeData = () => {
  return dataSource.value;
};

const addRootNode = () => {
  const newNode: T = {
    id: nanoid(),
    parentId: '-1',
    children: [],
    isEdit: true,
    [props.treeProps.label]: '', // 动态设置 label 属性名
    ...(props.treeProps.code ? { [props.treeProps.code]: '' } : {}), // 如果存在 code 字段也加上
  } as unknown as T;

  dataSource.value = [newNode];
};

defineExpose({ setCurrentKey, getCurrentNode, setTreeData, getTreeData });
</script>

<style lang="scss" scoped>
.dw-tree {
  margin-top: 10px;
  :deep(.el-form-item) {
    margin-bottom: 0;
  }
  .search-warpper {
    width: calc(100% - 20px);
    margin: 5px auto;
  }

  .tree-node,
  .tree-node-edit {
    display: flex;
    justify-content: space-between;
    width: 100%;
    align-items: center;
  }
}
.icon:hover {
  cursor: pointer;
}
.icon.add:hover {
  color: blue;
}
.icon.del:hover {
  color: red;
}

.icon.save:hover {
  color: green;
}

.total {
  display: block;
}
.button-box {
  display: none;
}
.tree-node-edit:hover .button-box {
  display: block;
}
.tree-node-edit:hover .total {
  display: none;
}
</style>
